package com.ssy.lingxi.member.merchant.serviceimpl.web;

import com.ssy.lingxi.common.constant.basic.EnableDisableStatus;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.common.utils.Aes128Util;
import com.ssy.lingxi.common.utils.PasswordUtil;
import com.ssy.lingxi.member.merchant.config.ServiceConfig;
import com.ssy.lingxi.member.merchant.entity.*;
import com.ssy.lingxi.member.merchant.model.bo.AuthBO;
import com.ssy.lingxi.member.merchant.api.constant.MemberRelationTypeEnum;
import com.ssy.lingxi.member.merchant.model.constant.MemberUserAuthTypeEnum;
import com.ssy.lingxi.member.merchant.model.vo.maintenance.request.*;
import com.ssy.lingxi.member.merchant.model.vo.maintenance.response.MemberUserGetVO;
import com.ssy.lingxi.member.merchant.model.vo.maintenance.response.MemberUserQueryVO;
import com.ssy.lingxi.member.merchant.repository.MemberRepository;
import com.ssy.lingxi.member.merchant.repository.MemberUserRepository;
import com.ssy.lingxi.member.merchant.service.base.IBaseMemberCacheService;
import com.ssy.lingxi.member.merchant.service.web.IPlatformMemberUserService;
import com.ssy.lingxi.member.merchant.utils.AuthBOUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 平台后台 - 用户操作接口实现类
 * @author 万宁
 * @version 2.0.0
 * @date 2020-06-29
 */
@Service
public class PlatformMemberUserServiceImpl implements IPlatformMemberUserService {

    @Resource
    private MemberRepository memberRepository;

    @Resource
    private MemberUserRepository memberUserRepository;

    @Resource
    private IBaseMemberCacheService memberCacheService;

    /**
     * 新增用户
     * @param headers HttpHeaders信息
     * @param addVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> addMemberUser(HttpHeaders headers, MemberUserAddVO addVO) {
        UserLoginCacheDTO loginUser = memberCacheService.needLoginFromManagePlatform(headers);
        //幂等校验
        if(memberCacheService.existRegisterKey(addVO.getPhone(), true)) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_EXISTS);
        }

        if(StringUtils.hasLength(addVO.getEmail()) && memberCacheService.existRegisterKey(addVO.getEmail(), true)) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_EMAIL_EXISTS);
        }

        if(StringUtils.hasLength(addVO.getAccount()) && memberCacheService.existRegisterKey(addVO.getAccount(), true)) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_ACCOUNT_EXISTS);
        }

        memberCacheService.setRegisterKey(addVO.getPhone(), addVO.getEmail(), addVO.getAccount(), true);

        MemberDO memberDO = memberRepository.findById(loginUser.getMemberId()).orElse(null);
        if(memberDO == null) {
            memberCacheService.deleteRegisterKey(addVO.getPhone(), addVO.getEmail(), addVO.getAccount(), true);
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        if(memberDO.getUsers().stream().anyMatch(user -> user.getAccount().toLowerCase().equals(addVO.getAccount().toLowerCase()))) {
            memberCacheService.deleteRegisterKey(addVO.getPhone(), addVO.getEmail(), addVO.getAccount(), true);
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_ACCOUNT_EXISTS);
        }

        if(memberDO.getUsers().stream().anyMatch(user -> user.getPhone().equals(addVO.getPhone()))) {
            memberCacheService.deleteRegisterKey(addVO.getPhone(), addVO.getEmail(), addVO.getAccount(), true);
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_EXISTS);
        }

        if(StringUtils.hasLength(addVO.getEmail()) && memberDO.getUsers().stream().anyMatch(user -> user.getEmail().equals(addVO.getEmail()))) {
            memberCacheService.deleteRegisterKey(addVO.getPhone(), addVO.getEmail(), addVO.getAccount(), true);
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_EMAIL_EXISTS);
        }

        MemberOrganizationDO memberOrganizationDO = memberDO.getOrgs().stream().filter(c -> c.getId().equals(addVO.getOrgId())).findFirst().orElse(null);
        if(memberOrganizationDO == null) {
            memberCacheService.deleteRegisterKey(addVO.getPhone(), addVO.getEmail(), addVO.getAccount(), true);
            return Wrapper.fail(ResponseCode.MC_MS_ORGANIZATION_DOES_NOT_EXIST);
        }

        //设置权限
        Set<MemberRoleDO> memberRoleSet = new HashSet<>();
        for(Long roleId: addVO.getMemberRoleIds()) {
            MemberRoleDO memberRoleDO = memberDO.getMemberRoles().stream().filter(r -> r.getId().equals(roleId)).findFirst().orElse(null);
            if(memberRoleDO == null) {
                memberCacheService.deleteRegisterKey(addVO.getPhone(), addVO.getEmail(), addVO.getAccount(), true);
                return Wrapper.fail(ResponseCode.MC_MS_ROLE_DOES_NOT_EXIST);
            }

            if(memberRoleDO.getStatus().equals(EnableDisableStatus.DISABLE.getCode())) {
                memberCacheService.deleteRegisterKey(addVO.getPhone(), addVO.getEmail(), addVO.getAccount(), true);
                return Wrapper.fail(ResponseCode.MC_MS_ROLE_HAS_BEEN_DISABLED);
            }

            memberRoleSet.add(memberRoleDO);
        }

        MemberUserDO memberUserDO = new MemberUserDO();
        memberUserDO.setCreateTime(LocalDateTime.now());
        memberUserDO.setAccount(addVO.getAccount());
        memberUserDO.setName(addVO.getName());
        memberUserDO.setCountryCode(addVO.getCountryCode());
        memberUserDO.setPhone(addVO.getPhone());

        String encryptPassword;
        try {
            encryptPassword = PasswordUtil.instance().passwordToMd5String(Aes128Util.aesDecrypt(addVO.getPassword()));
        } catch (Exception e) {
            memberCacheService.deleteRegisterKey(addVO.getPhone(), addVO.getEmail(), addVO.getAccount(), true);
            return Wrapper.fail(ResponseCode.BUSINESS_ERROR);
        }

        memberUserDO.setPassword(encryptPassword);
        memberUserDO.setEmail(StringUtils.hasLength(addVO.getEmail()) ? addVO.getEmail().trim() : "");
        memberUserDO.setJobTitle(StringUtils.hasLength(addVO.getJobTitle()) ? addVO.getJobTitle().trim() : "");
        memberUserDO.setIdCardNo(StringUtils.hasLength(addVO.getIdCardNo()) ? addVO.getIdCardNo().trim() : "");
        memberUserDO.setLogo("");
        memberUserDO.setMember(memberDO);
        memberUserDO.setOrg(memberOrganizationDO);
        memberUserDO.setRoles(memberRoleSet);

        //合并权限
        List<List<AuthBO>> authList = memberRoleSet.stream().map(MemberRoleDO::getAuth).collect(Collectors.toList());
        MemberUserAuthDO userAuthDO = new MemberUserAuthDO();
        userAuthDO.setAuth(AuthBOUtils.mergeAndDistinct(authList));
        userAuthDO.setUser(memberUserDO);
        userAuthDO.setDataAuth(new ArrayList<>());
        userAuthDO.setChannelAuth(new ArrayList<>());
        userAuthDO.setChannels(new HashSet<>());

        memberUserDO.setUserAuth(userAuthDO);

        //用户是平台用户，还是会员用户
        memberUserDO.setRelType(MemberRelationTypeEnum.PLATFORM.getCode());
        //创建的用户为普通用户
        memberUserDO.setTypeEnum(MemberUserAuthTypeEnum.NORMAL.getCode());
        memberUserDO.setIsSales(EnableDisableStatus.DISABLE.getCode());
        memberUserDO.setStatus(EnableDisableStatus.ENABLE.getCode());

        memberUserRepository.saveAndFlush(memberUserDO);

        return Wrapper.success();
    }

    /**
     * 查询用户信息
     *
     * @param headers HttpHeaders信息
     * @param idVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<MemberUserGetVO> getMemberUser(HttpHeaders headers, MemberUserIdVO idVO) {
        UserLoginCacheDTO loginUser = memberCacheService.needLoginFromManagePlatform(headers);
        MemberDO memberDO = memberRepository.findById(loginUser.getMemberId()).orElse(null);
        if(memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        if(CollectionUtils.isEmpty(memberDO.getUsers())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        MemberUserDO userDO = memberDO.getUsers().stream().filter(u -> u.getId().equals(idVO.getUserId())).findFirst().orElse(null);
        if(userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        MemberUserGetVO getVO = new MemberUserGetVO();
        getVO.setUserId(userDO.getId());
        getVO.setAccount(userDO.getAccount());
        getVO.setName(userDO.getName());
        getVO.setCountryCode(StringUtils.hasLength(userDO.getCountryCode()) ? userDO.getCountryCode() : "");
        getVO.setPhone(userDO.getPhone());
        getVO.setEmail(StringUtils.hasLength(userDO.getEmail()) ? userDO.getEmail() : "");
        getVO.setIdCardNo(StringUtils.hasLength(userDO.getIdCardNo()) ? userDO.getIdCardNo() : "");
        getVO.setJobTitle(StringUtils.hasLength(userDO.getJobTitle()) ? userDO.getJobTitle() : "");
        if(userDO.getOrg() == null) {
            getVO.setOrgId(0L);
        } else {
            getVO.setOrgId(userDO.getOrg().getId());
        }

        if(CollectionUtils.isEmpty(userDO.getRoles())) {
            getVO.setMemberRoleIds(new ArrayList<>());
            getVO.setMemberRoleNames(new ArrayList<>());
        } else {
            getVO.setMemberRoleIds(userDO.getRoles().stream().map(MemberRoleDO::getId).collect(Collectors.toList()));
            getVO.setMemberRoleNames(userDO.getRoles().stream().map(MemberRoleDO::getRoleName).collect(Collectors.toList()));
        }

        return Wrapper.success(getVO);
    }

    /**
     * 更新用户
     * @param headers HttpHeaders信息
     * @param updateVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> updateMemberUser(HttpHeaders headers, MemberUserUpdateVO updateVO) {
        UserLoginCacheDTO loginUser = memberCacheService.needLoginFromManagePlatform(headers);
        MemberDO memberDO = memberRepository.findById(loginUser.getMemberId()).orElse(null);
        if(memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        MemberUserDO memberUserDO = memberUserRepository.findFirstByMemberAndId(memberDO, updateVO.getUserId());
        if(memberUserDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        //不能修改超级管理员账号
        if(memberUserDO.getTypeEnum().equals(MemberUserAuthTypeEnum.ADMIN.getCode())) {
            return Wrapper.fail(ResponseCode.MC_MS_FORBID_DELETE_OR_UPDATE_MEMBER_USER);
        }

        //不能修改当前登录的账号
        if(memberUserDO.getId().equals(loginUser.getUserId())) {
            return Wrapper.fail(ResponseCode.MC_MS_FORBID_DELTE_OR_UPDATE_CURRENT_LOGIN_USER);
        }

        MemberOrganizationDO memberOrganizationDO = memberDO.getOrgs().stream().filter(c -> c.getId().equals(updateVO.getOrgId())).findFirst().orElse(null);
        if(memberOrganizationDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_ORGANIZATION_DOES_NOT_EXIST);
        }

        //检查账号和手机号
        Specification<MemberUserDO> specification = (Specification<MemberUserDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.equal(root.get("relType").as(Integer.class), memberUserDO.getRelType()));
            list.add(criteriaBuilder.notEqual(root.get("id").as(Long.class), memberUserDO.getId()));
            list.add(criteriaBuilder.or(criteriaBuilder.equal(criteriaBuilder.lower(root.get("account").as(String.class)), updateVO.getAccount()),
                    criteriaBuilder.equal(root.get("phone").as(String.class), updateVO.getPhone())));
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        if (memberUserRepository.count(specification) > 0) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_ACCOUNT_OR_PHONE_EXISTS);
        }

        if(StringUtils.hasLength(updateVO.getEmail())) {
            specification = (Specification<MemberUserDO>) (root, query, criteriaBuilder) -> {
                List<Predicate> list = new ArrayList<>();
                list.add(criteriaBuilder.equal(root.get("relType").as(Integer.class), memberUserDO.getRelType()));
                list.add(criteriaBuilder.notEqual(root.get("id").as(Long.class), memberUserDO.getId()));
                list.add(criteriaBuilder.equal(root.get("email").as(String.class), updateVO.getEmail().trim()));
                Predicate[] p = new Predicate[list.size()];
                return criteriaBuilder.and(list.toArray(p));
            };

            if (memberUserRepository.count(specification) > 0) {
                return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_EMAIL_EXISTS);
            }
        }

        //设置权限
        Set<MemberRoleDO> memberRoleSet = new HashSet<>();
        for(long roleId: updateVO.getMemberRoleIds()) {
            MemberRoleDO memberRoleDO = memberDO.getMemberRoles().stream().filter(r -> r.getId() == roleId).findFirst().orElse(null);
            if(memberRoleDO == null) {
                return Wrapper.fail(ResponseCode.MC_MS_ROLE_DOES_NOT_EXIST);
            }

            if(memberRoleDO.getStatus().equals(EnableDisableStatus.DISABLE.getCode())) {
                return Wrapper.fail(ResponseCode.MC_MS_ROLE_HAS_BEEN_DISABLED);
            }

            memberRoleSet.add(memberRoleDO);
        }

        memberUserDO.setAccount(updateVO.getAccount());
        memberUserDO.setName(updateVO.getName());
        memberUserDO.setCountryCode(updateVO.getCountryCode());
        memberUserDO.setPhone(updateVO.getPhone());
        //不修改密码
        memberUserDO.setEmail(StringUtils.hasLength(updateVO.getEmail()) ? updateVO.getEmail().trim() : "");
        memberUserDO.setJobTitle(StringUtils.hasLength(updateVO.getJobTitle()) ? updateVO.getJobTitle().trim() : "");
        memberUserDO.setIdCardNo(StringUtils.hasLength(updateVO.getIdCardNo()) ? updateVO.getIdCardNo().trim() : "");
        memberUserDO.setOrg(memberOrganizationDO);
        memberUserDO.setRoles(memberRoleSet);

        //合并权限
        List<List<AuthBO>> authList = memberRoleSet.stream().map(MemberRoleDO::getAuth).collect(Collectors.toList());
        memberUserDO.getUserAuth().setAuth(AuthBOUtils.mergeAndDistinct(authList));

        memberUserRepository.saveAndFlush(memberUserDO);

        return Wrapper.success();
    }

    /**
     * 删除用户
     * @param headers HttpHeaders信息
     * @param idVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> deleteMemberUser(HttpHeaders headers, MemberUserIdVO idVO) {
        UserLoginCacheDTO loginUser = memberCacheService.needLoginFromManagePlatform(headers);
        MemberDO memberDO = memberRepository.findById(loginUser.getMemberId()).orElse(null);
        if(memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        MemberUserDO memberUserDO = memberUserRepository.findFirstByMemberAndId(memberDO, idVO.getUserId());
        if(memberUserDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        //不能修改会员创建时，自动创建的超级管理员用户
        if(memberUserDO.getTypeEnum().equals(MemberUserAuthTypeEnum.ADMIN.getCode())) {
            return Wrapper.fail(ResponseCode.MC_MS_FORBID_DELETE_OR_UPDATE_MEMBER_USER);
        }

        //不能删除账号本身
        if(memberUserDO.getId().equals(loginUser.getUserId())) {
            return Wrapper.fail(ResponseCode.MC_MS_FORBID_DELTE_OR_UPDATE_CURRENT_LOGIN_USER);
        }

        memberUserRepository.delete(memberUserDO);

        return Wrapper.success();
    }

    /**
     * 更改用户状态
     *
     * @param headers HttpHeaders信息
     * @param statusVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> updateMemberUserStatus(HttpHeaders headers, MemberUserUpdateStatusVO statusVO) {
        UserLoginCacheDTO loginUser = memberCacheService.needLoginFromManagePlatform(headers);
        MemberDO memberDO = memberRepository.findById(loginUser.getMemberId()).orElse(null);
        if(memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        MemberUserDO memberUserDO = memberUserRepository.findFirstByMemberAndId(memberDO, statusVO.getUserId());
        if(memberUserDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        //不能修改会员创建时，自动创建的超级管理员用户
        if(memberUserDO.getTypeEnum().equals(MemberUserAuthTypeEnum.ADMIN.getCode())) {
            return Wrapper.fail(ResponseCode.MC_MS_FORBID_DELETE_OR_UPDATE_MEMBER_USER);
        }

        //不能修改当前登录的账号
        if(memberUserDO.getId().equals(loginUser.getUserId())) {
            return Wrapper.fail(ResponseCode.MC_MS_FORBID_DELTE_OR_UPDATE_CURRENT_LOGIN_USER);
        }

        memberUserDO.setStatus(statusVO.getStatus());

        memberUserRepository.saveAndFlush(memberUserDO);

        return Wrapper.success();
    }

    /**
     * 分页查询用户
     * @param headers HttpHeaders信息
     * @param pageVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<PageData<MemberUserQueryVO>> pageMemberUser(HttpHeaders headers, PageQueryMemberUserVO pageVO) {
        UserLoginCacheDTO loginUser = memberCacheService.needLoginFromManagePlatform(headers);
        MemberDO memberDO = memberRepository.findById(loginUser.getMemberId()).orElse(null);
        if(memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        Pageable page = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize(), Sort.by("id").ascending());
        String account = StringUtils.hasLength(pageVO.getAccount()) ? pageVO.getAccount().trim() : "";
        String name = StringUtils.hasLength(pageVO.getName()) ? pageVO.getName().trim() : "";
        List<Integer> statusList = (pageVO.getStatus() == null || (!pageVO.getStatus().equals(EnableDisableStatus.DISABLE.getCode()) && !pageVO.getStatus().equals(EnableDisableStatus.ENABLE.getCode()))) ? EnableDisableStatus.toList() : Stream.of(pageVO.getStatus()).collect(Collectors.toList());

        Page<MemberUserDO> result = memberUserRepository.findByMemberAndAccountContainsAndNameContainsAndStatusIn(memberDO, account, name, statusList, page);
        List<MemberUserQueryVO> resultList = result.getContent().stream().map(u -> {
            MemberUserQueryVO queryVO = new MemberUserQueryVO();
            queryVO.setUserId(u.getId());
            queryVO.setAccount(u.getAccount());
            queryVO.setCountryCode(u.getCountryCode());
            queryVO.setLastLoginTime(u.getLastLoginTime() == null ? "" : u.getLastLoginTime().format(ServiceConfig.DEFAULT_DATETIME_FORMATTER));
            queryVO.setName(u.getName());
            queryVO.setPhone(u.getPhone());
            queryVO.setOrgName(u.getOrg() == null ? "" : u.getOrg().getTitle());
            String roleNames = "";
            if (!CollectionUtils.isEmpty(u.getRoles())) {
                roleNames = u.getRoles().stream().map(MemberRoleDO::getRoleName).collect(Collectors.joining(","));
            }
            queryVO.setRoleName(roleNames);
            queryVO.setStatus(u.getStatus());
            return queryVO;
        }).collect(Collectors.toList());

        return Wrapper.success(new PageData<>(result.getTotalElements(), resultList));
    }
}
